package org.lex.filter;

import java.util.Iterator;
import java.util.Vector;

import org.lex.utils.collections.Collections;


/**
 * �򵥵Ļ��ڹؼ��ֵĲ�ѯ���������£� include all : * * true * false include any : * * *
 * true false exclude all : true * false false false exclude any : * true false
 * false false ------------------------------------------------------- return
 * value: false false true true false
 * 
 * @author Daniel Liu
 */
public class KeywordFilter implements Filter<String> {
	public static enum Type {
		INCLUDE_ANY, INCLUDE_ALL, EXCLUDE_ANY, EXCLUDE_ALL
	};

	private Vector<String>[] keywords = null;

	// private boolean ignoreCase = true;

	public KeywordFilter() {
		this(true);
	}

	@SuppressWarnings("unchecked")
	public KeywordFilter(boolean ignoreCase) {
		super();
		this.keywords = new Vector[Type.values().length];
		for (int i = 0; i < keywords.length; i++)
			this.keywords[i] = new Vector<String>();
		// this.ignoreCase = ignoreCase;
	}

	/*
	 * convenient method for construction query
	 */
	public void add(KeywordFilter.Type type, String... keywords) {
		if (null == keywords || 0 == keywords.length)
			return;
		for (String key : keywords)
			Collections.addUniqueElement(this.keywords[type.ordinal()], key.toLowerCase());
	}

	public void remove(KeywordFilter.Type type, String... keywords) {
		if (null == keywords || 0 == keywords.length)
			return;
		for (String key : keywords)
			this.keywords[type.ordinal()].remove(key);
	}

	public boolean contains(KeywordFilter.Type type, String key) {
		return this.keywords[type.ordinal()].contains(key);
	}

	public Iterator<String> iterator(KeywordFilter.Type type) {
		return this.keywords[type.ordinal()].iterator();
	}

	public void clear(KeywordFilter.Type type) {
		this.keywords[type.ordinal()].clear();
	}

	public void clearAll() {
		for (Vector<String> vector : this.keywords)
			vector.clear();
	}

	public boolean isEmpty(KeywordFilter.Type type) {
		return this.keywords[type.ordinal()].isEmpty();
	}

	public boolean isEmpty() {
		for (Type type : Type.values())
			if (false == this.keywords[type.ordinal()].isEmpty())
				return false;
		return true;
	}

	public boolean accept(String o) {
		// check if o is null / String
		if (null == o)
			return false;
		// =======================
		// check if match keyword
		String str = ((CharSequence) o).toString().toLowerCase();
		// exclude any
		if (true == containsAny(str, keywords[Type.EXCLUDE_ANY.ordinal()]))
			return false;
		// exclude all
		if (true == containsAll(str, keywords[Type.EXCLUDE_ALL.ordinal()]))
			return false;
		// include any
		if (true == containsAny(str, keywords[Type.INCLUDE_ANY.ordinal()]))
			return true;
		// include all
		if (true == containsAll(str, keywords[Type.INCLUDE_ALL.ordinal()]))
			return true;
		// not contains any keyword
		return false;
	}

	/*
	 * ����str�Ƿ��vector���κ�һ���ؼ��� ���vectorΪ�գ�����false true : �� false:
	 * ����
	 */
	private boolean containsAny(String str, Vector<String> vector) {
		if (0 == vector.size())
			return false;
		/*
		 * ���Դ�Сд�������Щ���ӣ���ʱ�Ȳ�����
		 */
		for (String keyword : vector)
			if (str.length() >= keyword.length() && str.contains(keyword))
				return true;
		return false;
	}

	/*
	 * ����str�Ƿ��vector�����еĹؼ��� ���vectorΪ�գ�����false true : ������ false:
	 * �����ֻ���
	 */
	private boolean containsAll(String str, Vector<String> vector) {
		if (0 == vector.size())
			return false;
		/*
		 * ���Դ�Сд�������Щ���ӣ���ʱ�Ȳ�����
		 */
		for (String keyword : vector) {
			if (str.length() < keyword.length())
				return false;
			if (false == str.contains(keyword))
				return false;
		}
		return true;
	}

	public String toMultilineString() {
		return this.toString("\n");
	}

	public String toString() {
		return this.toString(" ; ");
	}

	private String toString(String sep) {
		StringBuilder buffer = new StringBuilder();
		Type[] all = Type.values();
		for (Type type : all)
			buffer.append(type.name()).append(keywords[type.ordinal()]).append(sep);
		buffer.setLength(buffer.length() - sep.length());
		return buffer.toString();
	}
}
